﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Windows.Forms;
using System.Configuration;
using System.Xml;
using System.Data.Linq;
using System.Drawing.Drawing2D;


namespace Marker
{
    
    public partial class MarkerMainForm : Form
    {
        #region Private Members

        private bool czyZainicjalizowany = false;
        private Bitmap obszarRysowania;
        private Point pozycjaMyszy;
        private List<String> typyUzytkownika;
        private Color aktualnyKolor;
        private Size aktualnyRozmiar;
        private PunktCharakterystyczny aktualnieZaznaczony;
        private bool czyZaznaczony;
        private List<Color> listaKolorowStd;
        private List<Color> listaKolorowUzytkownika;
        private List<ObrazPunkty> listaObrazow;
        private ObrazPunkty aktualnyObraz;

        private bool automatycznyZapis;
        private bool skalujObraz;
        private int maxIloscPunktow;

        private int h; //'global' variable used to keep height of original image
        private int w;  //'global' variable used to keep width of original image

        private enum TypyPunktowKolory
        {
            Nadgarstek = 0, Kostka, Opuszka, Wkleslosc,
        }

        public enum CzesciDloni
        {
            Nadgarstek, Kciuk, PalecWskazujacy, PalecSrodkowy, PalecSerdeczny, PalecMaly, TypyUzytkownika
        }

        public enum TypyPunktowNadgarstek
        {
            NadgarstekKciuk = 0, NadgarstekMaly
        }

        public enum TypyPunktowPalce
        {
            Kostka1 = 0, Kostka2, Kostka3, Opuszka, Wkleslosc
        }

        #endregion Private Members

        #region Constructors
        public MarkerMainForm()
        {
            InitializeComponent();
            Init();
        }
        #endregion Constructors

        #region Private Methods

        /// <summary>
        /// Metoda inicjalizująca formatkę. Wypełnia comboboxy, listę kolorów, pobiera ustawienia z pliku konfiguracyjnego.
        /// </summary>
        private void Init()
        {
            this.cbDlon.SelectedIndex = 0;

            this.typyUzytkownika = new List<string>();
            PobierzTypyZXML();
            WypelnijComboBoxy();
            cbTyp.SelectedIndex = 0;
            lblCount.Text = "0";

            //wypełnij listę kolorów
            this.listaKolorowStd = new List<Color>();
            listaKolorowStd.Add(Color.Red);
            listaKolorowStd.Add(Color.Green);
            listaKolorowStd.Add(Color.Yellow);
            listaKolorowStd.Add(Color.Blue);

            this.listaKolorowUzytkownika = new List<Color>();
            listaKolorowUzytkownika.Add(Color.BlueViolet);
            listaKolorowUzytkownika.Add(Color.Brown);
            listaKolorowUzytkownika.Add(Color.DarkGray);
            listaKolorowUzytkownika.Add(Color.DeepPink);
            listaKolorowUzytkownika.Add(Color.Ivory);
            listaKolorowUzytkownika.Add(Color.Olive);
            listaKolorowUzytkownika.Add(Color.Turquoise);

            this.aktualnyKolor = listaKolorowStd[(int)TypyPunktowKolory.Nadgarstek];
            this.btnKolor.BackColor = aktualnyKolor;
            this.aktualnyRozmiar = new Size(this.tbRozmiar.Value, this.tbRozmiar.Value);
            this.czyZaznaczony = false;
            this.listaObrazow = new List<ObrazPunkty>();

            //pobierz ustawienia z configu
            PobierzUstawienia();

            this.czyZainicjalizowany = true;
        }

        /// <summary>
        /// Metoda wypełniająca comboboxy cbCzesc, cbTYp oraz cbZazbaczonyCzesc odpowiednimi elementami pobranymi 
        /// z Enum'a CzesciDloni, TypyPunktówNagdarstek oraz TypyPunktówPalce
        /// </summary>
        private void WypelnijComboBoxy()
        {
            cbCzesc.Items.Clear();
            cbZaznaczonyCzesc.Items.Clear();
            foreach (CzesciDloni czesc in Enum.GetValues(typeof(CzesciDloni)))
            {
                cbCzesc.Items.Add(czesc.ToString());
                cbZaznaczonyCzesc.Items.Add(czesc.ToString());
            }
            cbCzesc.SelectedIndex = 0;
            cbZaznaczonyCzesc.SelectedIndex = -1;
            WypelnijCBTyp((int)CzesciDloni.Nadgarstek);
        }

        /// <summary>
        /// Na podstawie czesci dłoni oraz numeru dłoni podanych w parametrze wypelnia cbZaznaczonyTyp odpowiednimi elementami
        /// </summary>
        /// <param name="czescDloni">indeks części dłoni</param>
        /// <param name="dlon">indeks dłoni</param>
        private void WypelnijCBZaznaczonyTyp(int czescDloni, int dlon)
        {
            cbZaznaczonyTyp.Items.Clear();
            if (czescDloni == (int)CzesciDloni.TypyUzytkownika)
            {
                foreach (string typ in typyUzytkownika)
                {
                    cbZaznaczonyTyp.Items.Add(typ.ToString());
                }
            }
            else if (czescDloni > (int)CzesciDloni.Nadgarstek)    //palce
            {
                foreach (TypyPunktowPalce typ in Enum.GetValues(typeof(TypyPunktowPalce)))
                {

                    //jeżeli punkt danego typu już został dodany, nie dodawaj go do combo boxa, typ punktu można zmienić tylko na taki którego jeszcze nie ma
                    if (this.aktualnieZaznaczony.TypPalce != typ && this.aktualnyObraz.Punkty[dlon].Where(p => p.TypPalce == typ && (int)p.CzescDloni == czescDloni).ToList().Count > 0)
                        continue;

                    if ((int)this.aktualnieZaznaczony.CzescDloni != czescDloni && this.aktualnieZaznaczony.TypPalce == typ && this.aktualnyObraz.Punkty[dlon].Where(p => p.TypPalce == typ && (int)p.CzescDloni == czescDloni).ToList().Count > 0)
                        continue;

                    //przy kciuku mamy tylko 2 kostki, a mały palec nie ma wkleslosci
                    if ((czescDloni == (int)CzesciDloni.Kciuk && typ == TypyPunktowPalce.Kostka3) || (czescDloni == (int)CzesciDloni.PalecMaly && typ == TypyPunktowPalce.Wkleslosc))
                        continue;

                    cbZaznaczonyTyp.Items.Add(typ.ToString());
                }
            }
            else //nadgarstek
            {
                foreach (TypyPunktowNadgarstek typ in Enum.GetValues(typeof(TypyPunktowNadgarstek)))
                {
                    //jeżeli punkt danego typu już został dodany, nie dodawaj go do combo boxa, typ punktu można zmienić tylko na taki którego jeszcze nie ma
                    if (this.aktualnyObraz.Punkty[dlon].Where(p => p.CzescDloni == CzesciDloni.Nadgarstek && p.TypNadgarstek == typ).ToList().Count > 0 &&
                        ((this.aktualnieZaznaczony.CzescDloni == CzesciDloni.Nadgarstek && this.aktualnieZaznaczony.TypNadgarstek != typ) ||
                        (this.aktualnieZaznaczony.CzescDloni != CzesciDloni.Nadgarstek)))
                        continue;

                    cbZaznaczonyTyp.Items.Add(typ.ToString());
                }
            }
            cbZaznaczonyTyp.SelectedIndex = -1;
            cbZaznaczonyTyp.Text = "";
        }

        /// <summary>
        /// Na podstawie czesci dłoni podanej w parametrze wypelnia cbTyp odpowiednimi elementami
        /// </summary>
        /// <param name="czescDloni">indeks części dłoni</param>
        private void WypelnijCBTyp(int czescDloni)
        {
            cbTyp.Items.Clear();
            if (czescDloni == (int)CzesciDloni.TypyUzytkownika)
            {
                foreach (string typ in typyUzytkownika)
                {
                    cbTyp.Items.Add(typ.ToString());
                }
            }
            else if (czescDloni > (int)CzesciDloni.Nadgarstek)    //palce
            {
                foreach (TypyPunktowPalce typ in Enum.GetValues(typeof(TypyPunktowPalce)))
                {
                    //jeżeli punkt danego typu już został dodany, nie dodawaj go do combo boxa, typ punktu można zmienić tylko na taki którego jeszcze nie ma
                    if (this.aktualnyObraz != null && this.aktualnyObraz.Punkty.Count > 0 && this.aktualnyObraz.Punkty[cbDlon.SelectedIndex].Where(p => p.TypPalce == typ && (int)p.CzescDloni == czescDloni).ToList().Count > 0)
                        continue;

                    if ((czescDloni == (int)CzesciDloni.Kciuk && typ == TypyPunktowPalce.Kostka3) || (czescDloni == (int)CzesciDloni.PalecMaly && typ == TypyPunktowPalce.Wkleslosc))
                        continue;
                    cbTyp.Items.Add(typ.ToString());
                }
            }
            else //nadgarstek
            {
                foreach (TypyPunktowNadgarstek typ in Enum.GetValues(typeof(TypyPunktowNadgarstek)))
                {
                    //jeżeli punkt danego typu już został dodany, nie dodawaj go do combo boxa, typ punktu można zmienić tylko na taki którego jeszcze nie ma
                    if (this.aktualnyObraz != null && this.aktualnyObraz.Punkty.Count > 0 && this.aktualnyObraz.Punkty[cbDlon.SelectedIndex].Where(p => p.CzescDloni == CzesciDloni.Nadgarstek && p.TypNadgarstek == typ).ToList().Count > 0)
                        continue;

                    cbTyp.Items.Add(typ.ToString());
                }
            }
            if (cbTyp.Items.Count > 0)
                cbTyp.SelectedIndex = 0;
            else
            {
                cbTyp.SelectedIndex = -1;
                cbTyp.Text = "";
            }
        }

        /// <summary>
        /// Metoda pobierająca ustawienia z pliku konfiguracyjnego i zapisuje
        /// je do zmiennych this.automatycznyZapis, this.skalujObraz, this.maxIloscPunktow
        /// </summary>
        private void PobierzUstawienia()
        {
            //pobranie ustawien uzytkownika
            XmlDocument xml = new XmlDocument();
            xml.Load(Application.ProductName + ".exe.config");
            XmlNodeList ustawienia = xml.GetElementsByTagName("setting");
            foreach (XmlNode u in ustawienia)
            {
                try
                {
                    if (u.Attributes["name"].Value.Equals("automatycznyZapis"))
                        this.automatycznyZapis = bool.Parse(u.Attributes["value"].Value.ToString());
                    if (u.Attributes["name"].Value.Equals("skalujObraz"))
                        this.skalujObraz = bool.Parse(u.Attributes["value"].Value.ToString());
                    if (u.Attributes["name"].Value.Equals("maxIloscPunktow"))
                        this.maxIloscPunktow = int.Parse(u.Attributes["value"].Value.ToString());
                }
                catch (Exception exc)
                {
                    MessageBox.Show("Niepoprawna wartość w pliku konfiguracyjnym: " + u.Attributes["name"].ToString(), "Błąd");
                }
            }

            if (this.skalujObraz)
            {
                pbImage.Dock = DockStyle.Fill;
                pbImage.SizeMode = PictureBoxSizeMode.StretchImage;
            }
            else
            {
                pbImage.Dock = DockStyle.None;
                pbImage.SizeMode = PictureBoxSizeMode.AutoSize;
            }

            //pobranie typow
            PobierzTypyZXML();
            WypelnijComboBoxy();
        }

        /// <summary>
        /// Pobiera typy użytkownika z pliku konfiguracyjnego i zapisuje je do listy this.typyUzytkownika
        /// </summary>
        private void PobierzTypyZXML()
        {
            this.typyUzytkownika.Clear();
            XmlDocument xml = new XmlDocument();
            xml.Load(Application.ProductName + ".exe.config");
            XmlNodeList typy = xml.GetElementsByTagName("type");
            foreach (XmlNode node in typy)
                this.typyUzytkownika.Add(node.Attributes["name"].Value.ToString());
        }

        /// <summary>
        /// Metoda pobierająca punkty z pliku XML podanego w parametrze path.
        /// Punkty są zapisywane w obiekcie przekazywanym w drugim parametrze.
        /// </summary>
        /// <param name="path">Ścieżka do pliku</param>
        /// <param name="obraz">Obiekt przechowujący listę punktów oraz informację o obrazie</param>
        /// <returns>true w przypadku pomyślnego wykonaniua, false gdy nie uda się otworzyć pliku lub odczytać któregoś z jego elementów</returns>
        private bool PobierzPunktyZXML(string path, ref ObrazPunkty obraz)
        {
            bool result = true;
            try
            {
                XmlDocument oXmlDocument = new XmlDocument();
                oXmlDocument.Load(path);

                XmlNodeList dlonie = oXmlDocument.GetElementsByTagName("dlon");
                if (dlonie.Count > 0)
                {
                    for (int i = 0; i < dlonie.Count; i++)
                    {
                        XmlNodeList punkty = dlonie[i].ChildNodes;
                        foreach (XmlNode node in punkty)
                        {
                            string typ_s;
                            string czescDloni_s;

                            czescDloni_s = node.Attributes["kategoria"].Value;
                            CzesciDloni czescDloni;
                            if (DajCzescDloni(czescDloni_s, out czescDloni))
                            {
                                typ_s = node.Attributes["typ"].Value;
                                if (czescDloni == CzesciDloni.TypyUzytkownika)
                                {
                                    obraz.Punkty[i].Add(new PunktCharakterystyczny(new Point(int.Parse(node.Attributes["x"].Value), int.Parse(node.Attributes["y"].Value)), typ_s, i));
                                }
                                if (czescDloni == CzesciDloni.Nadgarstek)
                                {
                                    TypyPunktowNadgarstek typ;
                                    if (DajTypPunktuNadgarstek(typ_s, out typ))
                                        obraz.Punkty[i].Add(new PunktCharakterystyczny(new Point(int.Parse(node.Attributes["x"].Value), int.Parse(node.Attributes["y"].Value)), typ, i));
                                }
                                else
                                {
                                    TypyPunktowPalce typ;
                                    if (DajTypPunktuPalce(typ_s, out typ))
                                        obraz.Punkty[i].Add(new PunktCharakterystyczny(new Point(int.Parse(node.Attributes["x"].Value), int.Parse(node.Attributes["y"].Value)), czescDloni, typ, i));
                                }
                            }
                        }
                    }
                }
                else
                {
                    XmlNodeList punkty = oXmlDocument.GetElementsByTagName("punktCharakterystyczny");
                    obraz.Punkty[0].Clear();
                    obraz.Punkty[1].Clear();
                    foreach (XmlNode p in punkty)
                    {
                        obraz.Punkty[0].Add(new PunktCharakterystyczny(
                            new Point(int.Parse(p.Attributes["x"].Value), int.Parse(p.Attributes["y"].Value)),
                            p.Attributes["typ"].Value,
                            0));
                    }
                }

            }
            catch (Exception exc)
            {
                result = false;
            }
            return result;
        }

        /// <summary>
        /// Podaje Enum'a odpowiadającego stringowi podanemu jako pierwszy parametr.
        /// </summary>
        /// <param name="s">string</param>
        /// <param name="czesc">enum</param>
        /// <returns>true w razie powodzenia, false jeżeli nie odnaleziono odpowiedniego enuma</returns>
        private bool DajCzescDloni(string s, out CzesciDloni czesc)
        {
            bool result = false;
            czesc = CzesciDloni.Kciuk;
            foreach (CzesciDloni c in Enum.GetValues(typeof(CzesciDloni)))
            {
                if (s.Equals(c.ToString()))
                {
                    result = true;
                    czesc = c;
                    break;
                }
            }
            return result;
        }

        /// <summary>
        /// Podaje Enum'a odpowiadającego stringowi podanemu jako pierwszy parametr.
        /// </summary>
        /// <param name="s">string</param>
        /// <param name="typ">enum</param>
        /// <returns>true w razie powodzenia, false jeżeli nie odnaleziono odpowiedniego enuma</returns>
        private bool DajTypPunktuNadgarstek(string s, out TypyPunktowNadgarstek typ)
        {
            bool result = false;
            typ = TypyPunktowNadgarstek.NadgarstekKciuk;
            foreach (TypyPunktowNadgarstek t in Enum.GetValues(typeof(TypyPunktowNadgarstek)))
            {
                if (s.Equals(t.ToString()))
                {
                    result = true;
                    typ = t;
                    break;
                }
            }
            return result;
        }

        /// <summary>
        /// Podaje Enum'a odpowiadającego stringowi podanemu jako pierwszy parametr.
        /// </summary>
        /// <param name="s">string</param>
        /// <param name="typ">enum</param>
        /// <returns>true w razie powodzenia, false jeżeli nie odnaleziono odpowiedniego enuma</returns>
        private bool DajTypPunktuPalce(string s, out TypyPunktowPalce typ)
        {
            bool result = false;
            typ = TypyPunktowPalce.Opuszka;
            foreach (TypyPunktowPalce t in Enum.GetValues(typeof(TypyPunktowPalce)))
            {
                if (s.Equals(t.ToString()))
                {
                    result = true;
                    typ = t;
                    break;
                }
            }
            return result;
        }

        /// <summary>
        /// Metoda rysująca punkty charakterystyczne na obszarzeRysowania
        /// </summary>
        /// <param name="points">listy punktów charakterystycznych</param>
        private void RysujPunkty(List<List<PunktCharakterystyczny>> points)
        {
            if (this.aktualnyObraz.Obraz != null)
            {
                this.obszarRysowania.Dispose();
                Bitmap tmp = new Bitmap(this.aktualnyObraz.Obraz);
                Graphics g = Graphics.FromImage(tmp);
                Pen pen;
                for (int j = 0; j < cbDlon.Items.Count; j++)
                {
                    for (int i = 0; i < points[j].Count; i++)
                    {
                        PunktCharakterystyczny fp = points[j][i];
                        int index = -1;
                        if (fp.CzescDloni == CzesciDloni.TypyUzytkownika)
                        {
                            index = typyUzytkownika.IndexOf(fp.TypUzytkownika);
                            pen = new Pen(this.listaKolorowUzytkownika[index != -1 ? index : 0], this.aktualnyRozmiar.Height);
                        }
                        else
                        {
                            if (fp.CzescDloni == CzesciDloni.Nadgarstek)
                            {
                                index = (int)TypyPunktowKolory.Nadgarstek;
                            }
                            else
                            {
                                if (fp.TypPalce == TypyPunktowPalce.Opuszka)
                                    index = (int)TypyPunktowKolory.Opuszka;
                                else if (fp.TypPalce == TypyPunktowPalce.Wkleslosc)
                                    index = (int)TypyPunktowKolory.Wkleslosc;
                                else if (fp.TypPalce == TypyPunktowPalce.Kostka1 || fp.TypPalce == TypyPunktowPalce.Kostka2 || fp.TypPalce == TypyPunktowPalce.Kostka3)
                                    index = (int)TypyPunktowKolory.Kostka;
                            }

                            pen = new Pen(this.listaKolorowStd[index], this.aktualnyRozmiar.Height);
                        }

                        g.DrawEllipse(pen, new Rectangle(new Point(fp.X - (this.aktualnyRozmiar.Width / 2 + 1), fp.Y - (this.aktualnyRozmiar.Height / 2 + 1)), this.aktualnyRozmiar));
                    }
                }
                if (czyZaznaczony)
                {
                    pen = new Pen(Color.Lime, 2);
                    g.DrawEllipse(pen, new Rectangle(new Point(aktualnieZaznaczony.X - (this.aktualnyRozmiar.Width / 2 + 3), aktualnieZaznaczony.Y - (this.aktualnyRozmiar.Height / 2 + 3)), new Size(this.aktualnyRozmiar.Width + 3, this.aktualnyRozmiar.Height + 3)));
                }
                this.obszarRysowania = tmp;
                g.Dispose();
                if (cbRysujLinie.Checked)
                    RysujLinie();
                pbImage.Image = this.obszarRysowania;
                GC.Collect();
            }
        }

        /// <summary>
        /// Metoda wyszukująca punkt w charakterystyczny w punktach aktualnego obrazu w otoczeniu punktu podanego w parametrze. 
        /// Wykorzystywane w momencie kliknięcia na obrazie aby sprawdzić czy chcemy zaznaczyć istniejący punkt czy dodać nowy.
        /// </summary>
        /// <param name="p">punkt</param>
        /// <returns>lista odpowiadających punktów charakterystycznych</returns>
        private List<PunktCharakterystyczny> ZnajdzPunkt(Point p)
        {
            List<PunktCharakterystyczny> findResult = new List<PunktCharakterystyczny>();
            if (aktualnyObraz.Punkty.Count > 0)
            {
                for (int i = 0; i < cbDlon.Items.Count; i++)
                {
                    findResult.AddRange(aktualnyObraz.Punkty[i].FindAll(
                           delegate(PunktCharakterystyczny point)
                           {
                               return (Math.Abs(point.X - p.X) <= this.aktualnyRozmiar.Width / 2 && Math.Abs(point.Y - p.Y) <= this.aktualnyRozmiar.Height / 2); //(point.X == this.mousePosition.X && point.Y == this.mousePosition.Y));;
                           }
                           ));
                }
            }
            return findResult;
        }

        /// <summary>
        /// Metoda ustawiająca wszystkie elementy GUI związane z zaznaczonym punktem.
        /// </summary>
        /// <param name="p">punkt który chcemy zaznaczyć</param>
        private void ZaznaczPunkt(PunktCharakterystyczny p)
        {
            czyZaznaczony = true;
            aktualnieZaznaczony = p;
            cbZaznaczonyDlon.SelectedIndex = p.Dlon;
            lblSelectedX.Text = p.X.ToString();
            lblSelectedY.Text = p.Y.ToString();
            cbZaznaczonyCzesc.Enabled = true;
            cbZaznaczonyCzesc.SelectedItem = p.CzescDloni.ToString();
            WypelnijCBZaznaczonyTyp(cbZaznaczonyCzesc.SelectedIndex, cbZaznaczonyDlon.SelectedIndex);
            cbZaznaczonyTyp.Enabled = true;

            if (p.CzescDloni == CzesciDloni.TypyUzytkownika)
                cbZaznaczonyTyp.SelectedItem = p.TypUzytkownika;
            else
                cbZaznaczonyTyp.SelectedItem = p.CzescDloni == (int)CzesciDloni.Nadgarstek ? p.TypNadgarstek.ToString() : p.TypPalce.ToString();
        }

        /// <summary>
        /// Metoda resetująca wszystkie ustawienia GUI związane z zaznaczonym punktem
        /// </summary>
        private void OdznaczPunkt()
        {
            if (this.czyZaznaczony)
            {
                this.czyZaznaczony = false;
                lblSelectedX.Text = "";
                lblSelectedY.Text = "";
                cbZaznaczonyTyp.SelectedIndex = -1;
                cbZaznaczonyTyp.Enabled = false;
                cbZaznaczonyCzesc.SelectedIndex = -1;
                cbZaznaczonyCzesc.Enabled = false;
            }
        }

        /// <summary>
        /// Metoda zapisująca punkty aktualnego obrazu do XMLa
        /// </summary>
        /// <param name="path">ścieżka do pliku XML</param>
        /// <returns>ture w razie powodzenia, w przeciwnym przypadku false</returns>
        private bool ZapiszDoXML(string path)
        {
            bool result = false;
            try
            {
                XmlWriterSettings settings = new XmlWriterSettings();
                settings.Indent = true;
                settings.IndentChars = ("    ");
                using (XmlWriter writer = XmlWriter.Create(path, settings))
                {
                    writer.WriteStartElement("punktyCharakterystyczne");
                    for (int i = 0; i < this.aktualnyObraz.Punkty.Count; i++)
                    {
                        writer.WriteStartElement("dlon");
                        foreach (PunktCharakterystyczny point in this.aktualnyObraz.Punkty[i])
                        {
                            writer.WriteStartElement("punktCharakterystyczny");
                            writer.WriteAttributeString("x", point.X.ToString());
                            writer.WriteAttributeString("y", point.Y.ToString());
                            writer.WriteAttributeString("czescDloni", point.CzescDloni.ToString());
                            if (point.CzescDloni == CzesciDloni.TypyUzytkownika)
                                writer.WriteAttributeString("typ", point.TypUzytkownika);
                            else if (point.CzescDloni == CzesciDloni.Nadgarstek)
                                writer.WriteAttributeString("typ", point.TypNadgarstek.ToString());
                            else
                                writer.WriteAttributeString("typ", point.TypPalce.ToString());
                            writer.WriteEndElement();
                        }
                        writer.WriteEndElement();
                    }
                    writer.WriteEndElement();
                    writer.Flush();
                    result = true;
                }
            }
            catch (Exception exc)
            {
                MessageBox.Show("Nie udało się zapisac zmian!", "Błąd");
            }

            return result;
        }

        /// <summary>
        /// Metoda zapisująca punkty obrazu podanego w parametrze do XMLa
        /// </summary>
        /// <param name="path">ścieżka do pliku XML</param>
        /// <returns>ture w razie powodzenia, w przeciwnym przypadku false</returns>
        private bool ZapiszDoXML(ObrazPunkty obraz)
        {
            bool result = false;
            try
            {
                XmlWriterSettings settings = new XmlWriterSettings();
                settings.Indent = true;
                settings.IndentChars = ("    ");
                string sciezka = obraz.Folder + obraz.Nazwa.Substring(0, obraz.Nazwa.LastIndexOf(".") + 1) + "xml";
                using (XmlWriter writer = XmlWriter.Create(sciezka, settings))
                {
                    writer.WriteStartElement("punktyCharakterystyczne");
                    for (int i = 0; i < cbDlon.Items.Count; i++)
                    {
                        writer.WriteStartElement("dlon");
                        foreach (PunktCharakterystyczny p in obraz.Punkty[i])
                        {
                            writer.WriteStartElement("punktCharakterystyczny");
                            writer.WriteAttributeString("x", p.X.ToString());
                            writer.WriteAttributeString("y", p.Y.ToString());
                            writer.WriteAttributeString("kategoria", p.CzescDloni.ToString());
                            if (p.CzescDloni == CzesciDloni.TypyUzytkownika)
                                writer.WriteAttributeString("typ", p.TypUzytkownika);
                            else if (p.CzescDloni == CzesciDloni.Nadgarstek)
                                writer.WriteAttributeString("typ", p.TypNadgarstek.ToString());
                            else
                                writer.WriteAttributeString("typ", p.TypPalce.ToString());

                            writer.WriteEndElement();
                        }
                        writer.WriteEndElement();
                    }
                    writer.WriteEndElement();
                    writer.Flush();
                    result = true;
                }
            }
            catch (Exception exc)
            {
                result = false;
            }

            return result;
        }

        /// <summary>
        /// Metoda zapisująca punkty z wszystkich obrazów do XMLi i w razie potrzeby wyświetlająca odpowiedni komunikat
        /// </summary>
        /// <param name="pokazKomunikaty">parametr infromujący o tym czy chcemy otrzymać komunikat</param>
        private void ZapiszWszystko(bool pokazKomunikaty)
        {
            bool zapisano = true;
            foreach (ObrazPunkty o in listaObrazow)
            {
                if (!ZapiszDoXML(o))
                    zapisano = false;
            }
            if (zapisano && pokazKomunikaty)
                MessageBox.Show("Dane zostały zapisane!", "Sukces");
            else if (pokazKomunikaty)
                MessageBox.Show("Nie udało się zapisać wszystkich plików!", "Błąd");
        }

        

        /// <summary>
        /// Metoda ustawiajce wszystkie zmienne oraz GUI tak aby aktualnym obrazem był obraz o numerze
        /// podanym jako parametr.
        /// </summary>
        /// <param name="nr">numer obrazu</param>
        private void UstawObraz(int nr)
        {
            if (this.aktualnyObraz != null)
                aktualnyObraz.UsunObrazZPamieci();

            this.aktualnyObraz = listaObrazow[nr];
            
            this.aktualnyObraz.WczytajObraz();
         

            cbDlon.SelectedIndex = 0;
            txtNumerObrazu.Text = (nr + 1).ToString();
            lblNazwaObrazu.Text = aktualnyObraz.Nazwa;
            lblCount.Text = (this.aktualnyObraz.Punkty[0].Count + this.aktualnyObraz.Punkty[1].Count).ToString();
            if (this.obszarRysowania != null)
                this.obszarRysowania.Dispose();
            this.obszarRysowania = new Bitmap(this.aktualnyObraz.Obraz);
            pbImage.Image = this.obszarRysowania;
            this.czyZaznaczony = false;
            RysujPunkty(this.aktualnyObraz.Punkty);
            WypelnijComboBoxy();
            GC.Collect();

        }

        /// <summary>
        /// Metoda usuwająca punkt z aktualnego obrazu. Po usunieciu punkty następuje ponowne narysowanie wszystkich punktów,
        /// oraz odświerzenie comboboxów z dostępnymi typami punktów.
        /// </summary>
        /// <param name="p">punkt do usunięcia</param>
        private void UsunPunkt(PunktCharakterystyczny p)
        {
            if (aktualnieZaznaczony != null && aktualnieZaznaczony.X == p.X && aktualnieZaznaczony.Y == p.Y)
            {
                OdznaczPunkt();
                czyZaznaczony = false;
            }
            try
            {
                this.aktualnyObraz.Punkty[p.Dlon].Remove(p);
                RysujPunkty(this.aktualnyObraz.Punkty);
                WypelnijComboBoxy();
                lblCount.Text = (int.Parse(lblCount.Text) - 1).ToString();
            }
            catch (NullReferenceException)
            {
                MessageBox.Show("ERROR:Aby wykonać tą operację musisz najpierw wczytać plik.");

            }

        }

        /// <summary>
        /// Wpisuje nazwy obrazów do cbKobpiujZ
        /// </summary>
        private void OdswiezCBKopiujZ()
        {
            int i = 1;
            cbKopiujZ.Items.Clear();
            foreach (ObrazPunkty o in this.listaObrazow)
            {
                cbKopiujZ.Items.Add(i + ": " + o.Nazwa);
                i++;
            }
        }

        /// <summary>
        /// Metoda porównująca punkty charakterystyczne palca na podstawie indexu typu palca. 
        /// Wykorzystywane przy rysowaniu linii palców podczas sortowania punktów.
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        private int PorownajPunktyPalca(PunktCharakterystyczny x, PunktCharakterystyczny y)
        {
            if (x == null)
            {
                if (y == null)
                {
                    // If x is null and y is null, they're
                    // equal. 
                    return 0;
                }
                else
                {
                    // If x is null and y is not null, y
                    // is greater. 
                    return -1;
                }
            }
            else
            {
                // If x is not null...
                //
                if (y == null)
                // ...and y is null, x is greater.
                {
                    return 1;
                }
                else
                {
                    if ((int)x.TypPalce > (int)y.TypPalce)
                    {
                        // x wieksze
                        return 1;
                    }
                    else if ((int)x.TypPalce < (int)y.TypPalce)
                    {
                        // y wieksze
                        return -1;
                    }
                    else
                        return 0;
                }
            }
        }

        /// <summary>
        /// Rysuje linie łączące punkty na aktualnym obrazie.
        /// </summary>
        private void RysujLinie()
        {
            for (int i = 0; i < cbDlon.Items.Count; i++)
            {
                if (this.aktualnyObraz.Punkty[i].Where(p => p.CzescDloni == CzesciDloni.Nadgarstek).ToList().Count == 2)
                {
                    Graphics g = Graphics.FromImage(this.obszarRysowania);
                    List<PunktCharakterystyczny> punktyNadgarstka = this.aktualnyObraz.Punkty[i].Where(p => p.CzescDloni == CzesciDloni.Nadgarstek).ToList();
                    Point[] punkty;

                    //rysowanie palców
                    Pen pen = new Pen(Color.Yellow, 1);
                    Point punktStartowy = new Point((int)(0.5 * (punktyNadgarstka[0].X + punktyNadgarstka[1].X)), (int)(0.5 * (punktyNadgarstka[0].Y + punktyNadgarstka[1].Y)));
                    foreach (CzesciDloni czesc in Enum.GetValues(typeof(CzesciDloni)))
                    {
                        if (czesc != CzesciDloni.Nadgarstek && czesc != CzesciDloni.TypyUzytkownika)
                        {
                            List<PunktCharakterystyczny> punktyPalca = this.aktualnyObraz.Punkty[i].Where(p => p.CzescDloni == czesc).ToList();
                            if (punktyPalca.Count > 0)
                            {
                                punkty = new Point[punktyPalca.Count + 1];
                                punkty[0] = punktStartowy;
                                punktyPalca.Sort(PorownajPunktyPalca);
                                for (int j = 0; j < punktyPalca.Count; j++)
                                {
                                    punkty[j + 1] = new Point(punktyPalca[j].X, punktyPalca[j].Y);
                                }
                                g.DrawLines(pen, punkty);
                            }
                        }
                    }

                    //rysowanie wielokąta
                    pen.Color = Color.Orange;
                    List<PunktCharakterystyczny> konce = new List<PunktCharakterystyczny>();

                    //wyszkuiwanie koncow kazdego z palcow
                    PunktCharakterystyczny aktualnyKoniec = null;
                    foreach (CzesciDloni aktualnaCzesc in Enum.GetValues(typeof(CzesciDloni)))
                    {
                        if (aktualnaCzesc != CzesciDloni.Nadgarstek && aktualnaCzesc != CzesciDloni.TypyUzytkownika)
                        {
                            List<PunktCharakterystyczny> tmp = this.aktualnyObraz.Punkty[i].Where(p => p.CzescDloni == aktualnaCzesc).ToList();
                            for (int j = 0; j < tmp.Count; j++)
                            {
                                if (aktualnyKoniec == null || ((int)aktualnyKoniec.TypPalce < (int)tmp[j].TypPalce && tmp[j].TypPalce != TypyPunktowPalce.Wkleslosc))
                                {
                                    aktualnyKoniec = tmp[j]; ;
                                }
                            }
                            if (aktualnyKoniec != null)
                                konce.Add(aktualnyKoniec);
                            //dodanie wkleslosci jezeli zostala zaznaczona
                            List<PunktCharakterystyczny> wkleslosc = tmp.Where(p => p.TypPalce == TypyPunktowPalce.Wkleslosc).ToList();
                            if (wkleslosc.Count > 0)
                                konce.Add(wkleslosc[0]);
                        }
                        aktualnyKoniec = null;
                    }

                    punkty = new Point[konce.Count + 2];
                    punkty[0] = new Point(punktyNadgarstka.Where(p => p.TypNadgarstek == TypyPunktowNadgarstek.NadgarstekKciuk).Single().X, punktyNadgarstka.Where(p => p.TypNadgarstek == TypyPunktowNadgarstek.NadgarstekKciuk).Single().Y);
                    punkty[konce.Count + 1] = new Point(punktyNadgarstka.Where(p => p.TypNadgarstek == TypyPunktowNadgarstek.NadgarstekMaly).Single().X, punktyNadgarstka.Where(p => p.TypNadgarstek == TypyPunktowNadgarstek.NadgarstekMaly).Single().Y);
                    for (int j = 0; j < konce.Count; j++)
                    {
                        punkty[j + 1] = new Point(konce[j].X, konce[j].Y);
                    }
                    g.DrawLines(pen, punkty);

                    pbImage.Image = this.obszarRysowania;
                }
            }
        }

        #endregion Private Methods

        #region Event Handlers

        private void cbDlon_SelectedIndexChanged(object sender, EventArgs e)
        {
            WypelnijComboBoxy();
        }

        private void cbRysujLinie_CheckedChanged(object sender, EventArgs e)
        {
            try
            {
                RysujPunkty(this.aktualnyObraz.Punkty);

            }
            catch (NullReferenceException)
            {
                MessageBox.Show("ERROR:Aby wykonać tą operację musisz najpierw wczytać plik.");

            }
        }

        private void pbImage_MouseMove(object sender, MouseEventArgs e)
        {
            if (this.skalujObraz)
            {
                float stretchX = (float)pbImage.Image.Size.Width / (float)pbImage.Size.Width;
                float stretchY = (float)pbImage.Image.Size.Height / (float)pbImage.Size.Height;
                this.pozycjaMyszy = new Point(Convert.ToInt32(e.X * stretchX), Convert.ToInt32(e.Y * stretchY));
            }
            else
                this.pozycjaMyszy = new Point(e.X, e.Y);

            this.lblCoordsX.Text = pozycjaMyszy.X.ToString();
            this.lblCoordsY.Text = pozycjaMyszy.Y.ToString();
        }

        /// <summary>
        /// Zdarzenie pojawiające się po kliknięciu na obrazie. W razie l-kliku: dodaje nowy punkt 
        /// lub zaznacza istniejący punkt, w razie r-kliku: usuwa punkt.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pbImage_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                List<PunktCharakterystyczny> p = ZnajdzPunkt(this.pozycjaMyszy);
                if (p.Count == 0) // nie ma jeszcze takiego punktu
                {
                    if (this.aktualnyObraz.Punkty.Count < this.maxIloscPunktow)
                    {
                        if (cbTyp.Items.Count > 0)
                        {
                            //narysuj i dodaj punkt do listy   
                            PunktCharakterystyczny fp;
                            if (cbCzesc.SelectedIndex == (int)CzesciDloni.TypyUzytkownika)
                            {
                                fp = new PunktCharakterystyczny(this.pozycjaMyszy, cbTyp.SelectedItem.ToString(), cbDlon.SelectedIndex);
                            }
                            else if (cbCzesc.SelectedIndex == (int)CzesciDloni.Nadgarstek)
                            {
                                TypyPunktowNadgarstek typ;
                                DajTypPunktuNadgarstek(cbTyp.SelectedItem.ToString(), out typ);
                                fp = new PunktCharakterystyczny(this.pozycjaMyszy, typ, cbDlon.SelectedIndex);
                            }
                            else
                            {
                                TypyPunktowPalce typ;
                                CzesciDloni czesc;
                                DajCzescDloni(cbCzesc.SelectedItem.ToString(), out czesc);
                                DajTypPunktuPalce(cbTyp.SelectedItem.ToString(), out typ);
                                fp = new PunktCharakterystyczny(this.pozycjaMyszy, czesc, typ, cbDlon.SelectedIndex);
                            }
                            //RysujPunkt(fp);
                            this.aktualnyObraz.Punkty[cbDlon.SelectedIndex].Add(fp);
                            ZaznaczPunkt(fp);
                            lblCount.Text = ((this.aktualnyObraz.Punkty[0].Count + this.aktualnyObraz.Punkty[0].Count)/2).ToString();


                            CzesciDloni czescDloni;
                            TypyPunktowNadgarstek typNadgarstek = TypyPunktowNadgarstek.NadgarstekKciuk;
                            TypyPunktowPalce typPalce = TypyPunktowPalce.Kostka1;

                            //ustaw comboboxy na kolejny punkt
                            if (cbCzesc.SelectedIndex != (int)CzesciDloni.TypyUzytkownika)
                            {
                                if (cbTyp.SelectedIndex < cbTyp.Items.Count - 1)
                                {
                                    cbTyp.SelectedIndex++;
                                    DajCzescDloni(cbCzesc.SelectedItem.ToString(), out czescDloni);
                                    if (czescDloni == CzesciDloni.Nadgarstek)
                                        DajTypPunktuNadgarstek(cbTyp.SelectedItem.ToString(), out typNadgarstek);
                                    else
                                        DajTypPunktuPalce(cbTyp.SelectedItem.ToString(), out typPalce);
                                }
                                else
                                {
                                    if (cbCzesc.SelectedIndex < cbCzesc.Items.Count - 1)
                                        cbCzesc.SelectedIndex++;
                                    DajCzescDloni(cbCzesc.SelectedItem.ToString(), out czescDloni);
                                    if (cbTyp.SelectedIndex != -1)
                                    {
                                        if (czescDloni == CzesciDloni.Nadgarstek)
                                            DajTypPunktuNadgarstek(cbTyp.SelectedItem.ToString(), out typNadgarstek);
                                        else
                                            DajTypPunktuPalce(cbTyp.SelectedItem.ToString(), out typPalce);
                                    }
                                }

                                WypelnijComboBoxy();

                                cbCzesc.SelectedItem = czescDloni.ToString();
                                if (cbTyp.Items.Count > 0)
                                    cbTyp.SelectedItem = czescDloni == CzesciDloni.Nadgarstek ? typNadgarstek.ToString() : typPalce.ToString();
                            }
                            //if (cbRysujLinie.Checked)
                            //    RysujPunkty(this.aktualnyObraz.Punkty);
                        }
                    }
                    else
                        MessageBox.Show("Maksymalna liczba punktów na obrazie to " + this.maxIloscPunktow.ToString() + "!", "Błąd");
                }
                else // jest juz taki punkt
                {
                    //oznacz punkt
                    ZaznaczPunkt(p[0]);
                    RysujPunkty(this.aktualnyObraz.Punkty);
                }
            }
            else if (e.Button == System.Windows.Forms.MouseButtons.Right)
            {
                //usun punkt z obrazu i listy
                List<PunktCharakterystyczny> findResult = new List<PunktCharakterystyczny>();
                for (int j = 0; j < cbDlon.Items.Count; j++)
                {
                    findResult.AddRange(this.aktualnyObraz.Punkty[j].FindAll(
                    delegate(PunktCharakterystyczny point)
                    {
                        return (Math.Abs(point.X - pozycjaMyszy.X) <= this.aktualnyRozmiar.Width / 2 && Math.Abs(point.Y - pozycjaMyszy.Y) <= this.aktualnyRozmiar.Height / 2); //(point.X == this.mousePosition.X && point.Y == this.mousePosition.Y));
                    }
                    ));
                }

                if (findResult.Count != 0)
                {
                    if (findResult[0] == this.aktualnieZaznaczony)
                        OdznaczPunkt();
                    UsunPunkt(findResult[0]);
                }
            }
        }

        private void tbRozmiar_Scroll(object sender, EventArgs e)
        {
            this.aktualnyRozmiar = new Size(tbRozmiar.Value, tbRozmiar.Value);
            try
            {
                RysujPunkty(this.aktualnyObraz.Punkty);
                pbImage.Focus();
            }
            catch (NullReferenceException)
            {
                MessageBox.Show("ERROR:Aby wykonać tą operację musisz najpierw wczytać plik.");

            }
        }

        private void cbType_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (czyZainicjalizowany)
            {
                if (cbCzesc.SelectedIndex == (int)CzesciDloni.TypyUzytkownika)
                {
                    this.aktualnyKolor = listaKolorowUzytkownika[cbTyp.SelectedIndex];
                }
                else if (cbCzesc.SelectedIndex == (int)TypyPunktowKolory.Nadgarstek)
                {
                    //nadgarstek
                    this.aktualnyKolor = listaKolorowStd[(int)TypyPunktowKolory.Nadgarstek];
                }
                else
                {
                    if (cbTyp.SelectedItem.ToString().StartsWith("Kostk")) //kostki
                        this.aktualnyKolor = listaKolorowStd[(int)TypyPunktowKolory.Kostka];
                    else if (cbTyp.SelectedItem.ToString().StartsWith("Opuszk")) //opuszki
                        this.aktualnyKolor = listaKolorowStd[(int)TypyPunktowKolory.Opuszka];
                    else
                        this.aktualnyKolor = listaKolorowStd[(int)TypyPunktowKolory.Wkleslosc];
                }
                btnKolor.BackColor = this.aktualnyKolor;
            }
        }

        private void cbSelectedType_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (czyZainicjalizowany && czyZaznaczony)
            {
                List<PunktCharakterystyczny> fp = ZnajdzPunkt(new Point(int.Parse(lblSelectedX.Text), int.Parse(lblSelectedY.Text)));

                CzesciDloni czesc;
                DajCzescDloni(cbZaznaczonyCzesc.SelectedItem.ToString(), out czesc);
                fp[0].CzescDloni = czesc;
                if (czesc == CzesciDloni.TypyUzytkownika)
                {
                    fp[0].TypUzytkownika = cbZaznaczonyTyp.SelectedItem.ToString();
                }
                if (czesc == CzesciDloni.Nadgarstek)
                {
                    TypyPunktowNadgarstek typ;
                    DajTypPunktuNadgarstek(cbZaznaczonyTyp.SelectedItem.ToString(), out typ);
                    fp[0].TypNadgarstek = typ;
                }
                else
                {
                    TypyPunktowPalce typ;
                    DajTypPunktuPalce(cbZaznaczonyTyp.SelectedItem.ToString(), out typ);
                    fp[0].TypPalce = typ;
                }

                RysujPunkty(this.aktualnyObraz.Punkty);
            }
        }

        private void zarządzajTypamiPunktówToolStripMenuItem_Click(object sender, EventArgs e)
        {
            TypesDictionaryForm form = new TypesDictionaryForm(this.typyUzytkownika, this.listaKolorowUzytkownika, this.skalujObraz, this.automatycznyZapis, this.maxIloscPunktow);
            if (form.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                PobierzUstawienia();
                if (this.aktualnyObraz != null)
                    RysujPunkty(this.aktualnyObraz.Punkty);
            }
        }

        private void wczytajToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.openFileDialogIMG.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                OdznaczPunkt();
                foreach (string plik in openFileDialogIMG.FileNames)
                {
                    ObrazPunkty op = new ObrazPunkty(plik);
                    PobierzPunktyZXML(op.Folder + op.Nazwa.Substring(0, op.Nazwa.LastIndexOf(".") + 1) + "xml", ref op);
                    this.listaObrazow.Add(op);
                }
                OdswiezCBKopiujZ();
                if (listaObrazow.Count > 0)
                {
                    UstawObraz(0);
                    lblIloscObrazow.Text = this.listaObrazow.Count.ToString();
                    pbImage.Visible = true;
                    //RysujPunkty(this.aktualnyObraz.Punkty);
                }
                WypelnijComboBoxy();
            }

           // changing h and w variable to get original height and width of image
            w = pbImage.Width;
            h = pbImage.Height;

            if (w > h) // this if resize track ball which respond for resizing image
            {
                Resize.Maximum = (w*10);
                Resize.Value = 0;
                Resize.Minimum = -h;
            }
            else
            {
                Resize.Maximum = (h * 10);
                Resize.Value = 0;
                Resize.Minimum = -w;

            }



        }

        private void zapiszPlikZPunktamiToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (saveFileDialogXML.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                if (ZapiszDoXML(saveFileDialogXML.FileName))
                    MessageBox.Show("Dane zostały zapisane!", "Sukces");
                else
                    MessageBox.Show("Nie udało się zapisać danych!", "Błąd");
            }
        }

        private void btnClear_Click(object sender, EventArgs e)
        {

            try
            {
                foreach (List<PunktCharakterystyczny> lista in this.aktualnyObraz.Punkty)
                {
                    lista.Clear();
                }
                WypelnijComboBoxy();
                this.czyZaznaczony = false;
                RysujPunkty(this.aktualnyObraz.Punkty);
                lblCount.Text = "0";
            }
            catch (NullReferenceException)
            {
                MessageBox.Show("ERROR:Aby wykonać tą operację musisz najpierw wczytać plik.");

            }







        }

        private void wczytajPlikZPunktamiToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.aktualnyObraz != null)
            {
                if (openFileDialogXML.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {

                    if (PobierzPunktyZXML(openFileDialogXML.FileName, ref this.aktualnyObraz))
                    {
                        czyZaznaczony = false;
                        RysujPunkty(this.aktualnyObraz.Punkty);
                        lblCount.Text = (this.aktualnyObraz.Punkty[0].Count + this.aktualnyObraz.Punkty[1].Count).ToString();
                    }
                    else
                        MessageBox.Show("Nie udało się pobrać danych z pliku!", "Błąd");
                }
            }
            else
                MessageBox.Show("Najpierw wczytaj obraz!", "Błąd");
        }

        private void btnPoprzedniObraz_Click(object sender, EventArgs e)
        {
            if (automatycznyZapis)
                ZapiszDoXML(this.aktualnyObraz);
            int nr = int.Parse(txtNumerObrazu.Text) - 1;
            if (nr > 0)
                UstawObraz(nr - 1);
        }

        private void btnNastepnyObraz_Click(object sender, EventArgs e)
        {
            if (automatycznyZapis)
                ZapiszDoXML(this.aktualnyObraz);
            int nr = int.Parse(txtNumerObrazu.Text) + 1;
            if (nr <= this.listaObrazow.Count)
                UstawObraz(nr - 1);

        }

        private void zapiszWszystkiePlikiZPunktamiToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ZapiszWszystko(true);
        }

        private void zapiszAktualnyPlikZPunktamiToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (ZapiszDoXML(this.aktualnyObraz))
                MessageBox.Show("Dane zostały zapisane!", "Sukces");
            else
                MessageBox.Show("Nie udało się zapisac zmian!", "Błąd");
        }

        private void txtNumerObrazu_TextChanged(object sender, EventArgs e)
        {
            try
            {
                int nr = int.Parse(txtNumerObrazu.Text);
                if (nr > 0 && nr <= listaObrazow.Count)
                    UstawObraz(nr - 1);
            }
            catch (FormatException exc)
            {
            }
        }

        private void txtNumerObrazu_MouseClick(object sender, MouseEventArgs e)
        {
            txtNumerObrazu.Select(0, txtNumerObrazu.Text.Length);
        }

        private void cbKopiujZ_SelectedIndexChanged(object sender, EventArgs e)
        {
            for (int i = 0; i < this.aktualnyObraz.Punkty.Count; i++)
            {
                this.aktualnyObraz.Punkty[i] = new List<PunktCharakterystyczny>(listaObrazow[cbKopiujZ.SelectedIndex].Punkty[i]);
            }
            RysujPunkty(this.aktualnyObraz.Punkty);
            lblCount.Text = (this.aktualnyObraz.Punkty[0].Count + this.aktualnyObraz.Punkty[1].Count).ToString();
        }

        private void MarkerMainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (this.automatycznyZapis)
                ZapiszWszystko(false);
        }

        private void btnUsunZaznaczony_Click(object sender, EventArgs e)
        {
            OdznaczPunkt();
            UsunPunkt(this.aktualnieZaznaczony);
        }

        private void btnUsunObraz_Click(object sender, EventArgs e)
        {
            this.listaObrazow.Remove(this.aktualnyObraz);
            lblIloscObrazow.Text = this.listaObrazow.Count.ToString();
            OdznaczPunkt();
            OdswiezCBKopiujZ();
            if (this.listaObrazow.Count > 0)
            {
                int nr = int.Parse(txtNumerObrazu.Text) - 1;
                if (nr > 0)
                    UstawObraz(nr - 1);
                else if (nr == 0)
                {
                    UstawObraz(nr);
                }
            }
            else
            {
                txtNumerObrazu.Text = "0";
                this.pbImage.Visible = false;
                lblNazwaObrazu.Text = "";
                lblCount.Text = "0";
            }

        }

        private void cbCzesc_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (czyZainicjalizowany)
            {
                WypelnijCBTyp(cbCzesc.SelectedIndex);
            }
        }

        private void cbZaznaczonyCzesc_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (czyZainicjalizowany)
            {
                if (cbZaznaczonyCzesc.SelectedIndex != -1)
                {
                    WypelnijCBZaznaczonyTyp(cbZaznaczonyCzesc.SelectedIndex, cbZaznaczonyDlon.SelectedIndex);
                }
            }
        }

        #endregion Event Handlers

        #region Classes

        /// <summary>
        /// Klasa za pomocą której przechowywane są informacje o punktach charakterystycznych
        /// </summary>
        public class PunktCharakterystyczny
        {
            #region Constructors
            public PunktCharakterystyczny(Point p, Marker.MarkerMainForm.TypyPunktowNadgarstek typ, int dlon)
            {
                X = p.X;
                Y = p.Y;
                Dlon = dlon;
                CzescDloni = Marker.MarkerMainForm.CzesciDloni.Nadgarstek;
                TypNadgarstek = typ;
            }

            public PunktCharakterystyczny(Point p, Marker.MarkerMainForm.CzesciDloni czesc, Marker.MarkerMainForm.TypyPunktowPalce typ, int dlon)
            {
                X = p.X;
                Y = p.Y;
                Dlon = dlon;
                CzescDloni = czesc;
                TypPalce = typ;
            }

            public PunktCharakterystyczny(Point p, string typUzytkownika, int dlon)
            {
                X = p.X;
                Y = p.Y;
                Dlon = dlon;
                CzescDloni = CzesciDloni.TypyUzytkownika;
                TypUzytkownika = typUzytkownika;
            }
            #endregion Constructors

            #region Public Members

            /// <summary>
            /// index dłoni do której należy punkt
            /// </summary>
            public int Dlon
            {
                get;
                set;
            }

            /// <summary>
            /// Współrzędna X punktu
            /// </summary>
            public int X
            {
                get;
                set;
            }

            /// <summary>
            /// Współrzędna Y punktu
            /// </summary>
            public int Y
            {
                get;
                set;
            }

            /// <summary>
            /// Część dłoni do której należy punkt
            /// </summary>
            public Marker.MarkerMainForm.CzesciDloni CzescDloni
            {
                get;
                set;
            }

            /// <summary>
            /// Jeżeli punkt należy do nadgarstka to jest to typ tego punktu
            /// </summary>
            public Marker.MarkerMainForm.TypyPunktowNadgarstek TypNadgarstek
            {
                get;
                set;
            }

            /// <summary>
            /// Jeżeli punkt należy do palców to jest to typ tego punktu
            /// </summary>
            public Marker.MarkerMainForm.TypyPunktowPalce TypPalce
            {
                get;
                set;
            }

            /// <summary>
            /// Jeżeli punkt należy do typów użytkownika to jest to typ tego punktu
            /// </summary>
            public string TypUzytkownika
            {
                get;
                set;
            }

            #endregion Public Members
        }

        /// <summary>
        /// Klasa przechowująca informacje o pliku obrazu oraz punktach zaznaczonych na obrazie
        /// </summary>
        public class ObrazPunkty
        {
            #region Constructors
            public ObrazPunkty(string sciezka)
            {
                Folder = sciezka.Substring(0, sciezka.LastIndexOf("\\") + 1);
                Punkty = new List<List<PunktCharakterystyczny>>();
                Punkty.Add(new List<PunktCharakterystyczny>());
                Punkty.Add(new List<PunktCharakterystyczny>());
                Nazwa = sciezka.Substring(sciezka.LastIndexOf("\\") + 1);
            }
            #endregion Constructors

            #region Public Methods
           

            /// <summary>
            /// Metoda wczytująca obraz do pamięci
            /// </summary>
            /// <returns></returns>
            public bool WczytajObraz()
            {
                bool result = true;
                try
                {
                    Obraz = new Bitmap(Folder + "\\" + Nazwa);
                    
                }
                catch (Exception exc)
                {
                    result = false;
                }
                return result;
            }

            /// <summary>
            /// Metoda usuwająca obraz z pamięci
            /// </summary>
            /// <returns></returns>
            public void UsunObrazZPamieci()
            {
                Obraz.Dispose();
            }

            #endregion Public Methods

            #region Public Members

            /// <summary>
            /// Ścieżja do folderu zawierającego obraz
            /// </summary>
            public string Folder
            {
                get;
                set;
            }

            /// <summary>
            /// Nazwa pliku obrazu
            /// </summary>
            public string Nazwa
            {
                get;
                set;
            }

            /// <summary>
            /// Listy punktów charakterystycznych
            /// </summary>
            public List<List<PunktCharakterystyczny>> Punkty
            {
                get;
                set;
            }

            /// <summary>
            /// Bitmapa obrazu
            /// </summary>
            public Bitmap Obraz
            {
                get;
                set;
            }
            #endregion Public Members
        }
        #endregion Classes

        #region Keyboard

        /// <summary>
        /// Metoda reagująca na skróty klawiszowe
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="keyData"></param>
        /// <returns></returns>
        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            switch (keyData)
            {
                case Keys.Down:
                case Keys.Up:
                case Keys.Left:
                case Keys.Right:
                    {
                        //przesuwanie zaznaczonego punktu
                        if (czyZaznaczony)
                        {
                            switch (keyData)
                            {
                                case Keys.Left:
                                    if (this.aktualnieZaznaczony.X > 0)
                                    {
                                        this.aktualnieZaznaczony.X--;
                                    }
                                    break;
                                case Keys.Right:
                                    if (this.aktualnieZaznaczony.X < w)
                                    {
                                        this.aktualnieZaznaczony.X++;
                                    }
                                    break;
                                case Keys.Up:
                                    if (this.aktualnieZaznaczony.Y > 0)
                                    {
                                        this.aktualnieZaznaczony.Y--;
                                    }
                                    break;
                                case Keys.Down:
                                    if (this.aktualnieZaznaczony.Y < h)
                                    {
                                        this.aktualnieZaznaczony.Y++;
                                    }
                                    break;
                            }
                            lblSelectedX.Text = this.aktualnieZaznaczony.X.ToString();
                            lblSelectedY.Text = this.aktualnieZaznaczony.Y.ToString();
                            RysujPunkty(this.aktualnyObraz.Punkty);
                        }
                        return true;
                    }
                case Keys.Back:
                    {
                        //usuniecie ostatnio dodanego punktu
                        if (this.aktualnieZaznaczony != null && czyZaznaczony)
                        {
                            int dlon = this.aktualnieZaznaczony.Dlon;
                            CzesciDloni czesc = this.aktualnieZaznaczony.CzescDloni;
                            TypyPunktowPalce typPalce = this.aktualnieZaznaczony.TypPalce;
                            TypyPunktowNadgarstek typNadgarstek = this.aktualnieZaznaczony.TypNadgarstek;

                            UsunPunkt(this.aktualnieZaznaczony);
                            WypelnijComboBoxy();
                            if (this.aktualnyObraz.Punkty[dlon].Count > 0)
                                ZaznaczPunkt(this.aktualnyObraz.Punkty[dlon].Last());

                            cbCzesc.SelectedItem = czesc.ToString();
                            cbTyp.SelectedItem = czesc == CzesciDloni.Nadgarstek ? typNadgarstek.ToString() : typPalce.ToString();
                        }
                        return true;
                    }
                case Keys.PageDown:
                case Keys.PageUp:
                    {
                        // przeskakiwanie po zaznaczonych punktach
                        if (this.aktualnyObraz != null && (this.aktualnyObraz.Punkty[0].Count > 0 || this.aktualnyObraz.Punkty[1].Count > 0))
                        {
                            int dlon = -1;
                            int index;

                            if (this.aktualnieZaznaczony != null)
                            {
                                index = this.aktualnyObraz.Punkty[this.aktualnieZaznaczony.Dlon].IndexOf(this.aktualnieZaznaczony);
                                dlon = this.aktualnieZaznaczony.Dlon;
                            }
                            else
                            {
                                index = -1;
                                dlon = -1;
                            }

                            if (keyData.Equals(Keys.PageDown) && index == -1)
                            {
                                if (this.aktualnyObraz.Punkty[1].Count > 0)
                                {
                                    index = this.aktualnyObraz.Punkty[1].Count - 1;
                                    dlon = 1;
                                }
                                else
                                {
                                    index = this.aktualnyObraz.Punkty[0].Count - 1;
                                    dlon = 0;
                                }
                            }

                            else if (keyData.Equals(Keys.PageUp) && index == -1)
                            {
                                dlon = 0;
                                index = 0;
                            }
                            else
                            {
                                if (keyData.Equals(Keys.PageDown))
                                {
                                    if (index == 0)
                                    {
                                        int tmp = (dlon + 1) % this.aktualnyObraz.Punkty.Count;
                                        dlon = this.aktualnyObraz.Punkty[tmp].Count > 0 ? tmp : dlon;
                                        index = this.aktualnyObraz.Punkty[dlon].Count - 1;
                                    }
                                    else
                                        index--;
                                }
                                else
                                {
                                    if (index == this.aktualnyObraz.Punkty[this.aktualnieZaznaczony.Dlon].Count - 1)
                                    {
                                        int tmp = (dlon + 1) % this.aktualnyObraz.Punkty.Count;
                                        dlon = this.aktualnyObraz.Punkty[tmp].Count > 0 ? tmp : dlon;
                                        index = 0;
                                    }
                                    else
                                        index++;

                                }
                            }
                            ZaznaczPunkt(this.aktualnyObraz.Punkty[dlon][index]);
                            WypelnijCBZaznaczonyTyp(cbZaznaczonyCzesc.SelectedIndex, cbZaznaczonyDlon.SelectedIndex);
                            if (this.aktualnieZaznaczony.CzescDloni == CzesciDloni.TypyUzytkownika)
                                cbZaznaczonyTyp.SelectedItem = this.aktualnieZaznaczony.TypUzytkownika;
                            else if (this.aktualnieZaznaczony.CzescDloni == CzesciDloni.Nadgarstek)
                                cbZaznaczonyTyp.SelectedItem = this.aktualnieZaznaczony.TypNadgarstek.ToString();
                            else
                                cbZaznaczonyTyp.SelectedItem = this.aktualnieZaznaczony.TypPalce.ToString();
                            RysujPunkty(this.aktualnyObraz.Punkty);
                        }
                        return true;
                    }
                case Keys.Enter:
                    {
                        //przejscie do kolejnego obrazu
                        btnNastepnyObraz.PerformClick();
                        return true;
                    }
                case Keys.Space:
                    {
                        //przejscie do kolejnego typu punktu

                        CzesciDloni czesc;
                        DajCzescDloni(cbCzesc.SelectedItem.ToString(), out czesc);

                        if (czesc == CzesciDloni.Nadgarstek && cbTyp.Items.Count > 0)
                        {
                            MessageBox.Show("Nie można pominąć punktów nadgarstka!", "Błąd");
                        }
                        else
                        {
                            if (cbTyp.SelectedIndex < cbTyp.Items.Count - 1)
                                cbTyp.SelectedIndex++;
                            else
                            {
                                do
                                {
                                    if (cbCzesc.SelectedIndex < cbCzesc.Items.Count - 1)
                                    {
                                        cbCzesc.SelectedIndex++;
                                        if (cbTyp.Items.Count > 0)
                                            cbTyp.SelectedIndex = 0;
                                    }
                                    else
                                        break;
                                }
                                while (cbTyp.Items.Count == 0);
                            }
                        }
                        return true;
                    }
                default:
                    return base.ProcessCmdKey(ref msg, keyData);
            }
        }

        #endregion Keyboard

        private void label14_Click(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {

        }

        private void Resizing_Enter(object sender, EventArgs e)
        {

        }

        private void label14_Click_1(object sender, EventArgs e)
        {

        }

        private void CProtocol_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void FixToWindow_CheckedChanged(object sender, EventArgs e)//this function makes image filed 460x460 and filling it with image
        {
            
                try{
                this.pnlImage.Height = 440;
                this.pnlImage.Width = 460;
                //pbImage.Image = Image.FromFile(@"C:\a\t.gif");
                pbImage.Dock = DockStyle.Fill;
                pbImage.SizeMode = PictureBoxSizeMode.StretchImage;
                }
                catch (NullReferenceException)
                {
                    MessageBox.Show("ERROR:Aby wykonać tą operację musisz najpierw wczytać plik.");

                }
            
         
            

        }

        private void Resize_Scroll(object sender, EventArgs e) //changing size of image filed and filling it with image -> resize:D
        {
            // h and w are 'global' variables height and width of original picture
            try{

            if (HoldRatio.Checked == true)
            {
                int newh = h + Resize.Value; 
                int neww = w + Resize.Value;
                this.pbImage.Height = newh;
                this.pbImage.Width = neww;
                this.pnlImage.Height = newh;
                this.pnlImage.Width = neww;
                pbImage.Dock = DockStyle.Fill;
                pbImage.SizeMode = PictureBoxSizeMode.StretchImage;
            }
            }
            catch (NullReferenceException)
            {
                MessageBox.Show("ERROR:Aby wykonać tą operację musisz najpierw wczytać plik.");

            }

        }

        private void flowLayoutPanel2_Paint(object sender, PaintEventArgs e) //container which in created to prevent overextend of images while scaling
        {

        }

        
    }
}
